package it.polimi.traveldream.managers;

import it.polimi.traveldream.managers.credentials.UserCredentialManager;
import it.polimi.traveldream.persistence.Aeroporto;
import it.polimi.traveldream.persistence.Compagnia;
import it.polimi.traveldream.persistence.Hotel;
import it.polimi.traveldream.persistence.Localita;
import it.polimi.traveldream.persistence.Tour;
import it.polimi.traveldream.persistence.TrattaVolo;
import it.polimi.traveldream.persistence.Utente;
import it.polimi.traveldream.persistence.dtos.AeroportoDTO;
import it.polimi.traveldream.persistence.dtos.CompagniaDTO;
import it.polimi.traveldream.persistence.dtos.LocalitàDTO;
import it.polimi.traveldream.persistence.dtos.HotelProdDTO;
import it.polimi.traveldream.persistence.dtos.TourProdDTO;
import it.polimi.traveldream.persistence.dtos.TrattaProdDTO;

import java.util.ArrayList;
import java.util.List;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Stateless
public class ProductManagerImpl implements ProductManager {

	@PersistenceContext
	private EntityManager em;

	// @EJB(beanName="UserCredentialManagerImpl")
	private UserCredentialManager userMgr;

	private UserCredentialManagerImpl getUserCredManager() {
		return (UserCredentialManagerImpl) userMgr;
		
	}

	
	public Utente findUtenteEntity(String email) {
		return em.find(Utente.class, email);
	}
	
	
	//località
	@Override
	public int saveLocalità(LocalitàDTO localitàDTO) {
		Localita località = convert(localitàDTO);
		em.persist(località);
		return località.getIDLocalita();
	}

	@Override
	public void updateBasicInformationsLocalità(LocalitàDTO localitàDTO) {
		Localita località = findLocalitaEntity(localitàDTO.getID());
		updateEntityBasicFields(localitàDTO, località);
		em.merge(località);
	}

	@Override
	public void deleteLocalità(int localitàDTOID) {
		em.remove(findLocalitaEntity(localitàDTOID));
	}

	@Override
	public LocalitàDTO findLocalità(int localitàDTOID) {
		return convert(findLocalitaEntity(localitàDTOID));
	}

	@Override
	public List<LocalitàDTO> findAllLocalità() {
		List<Localita> località = em.createNamedQuery(Localita.FIND_ALL, Localita.class).getResultList();
		return ConverterFactory.convertList(località, new ConverterFactory.ConverterCallback<Localita, LocalitàDTO>() {

			@Override
			public LocalitàDTO autoConvert(Localita dto) {
				return convert(dto);
			}
		});
	}

	public Localita findLocalitaEntity(int localitàID) {
		return em.find(Localita.class, localitàID);
	}

	public String getLocAero(int localitàID){
		Localita loc = em.find(Localita.class, localitàID);
		return loc.getNome();
	}
	
	public LocalitàDTO convert(Localita località) {
		LocalitàDTO loc = new LocalitàDTO();
		loc.setDescrizione(località.getDescrizione());
		loc.setID(località.getIDLocalita());
		loc.setNome(località.getNome());
		loc.setProvincia(località.getProvincia());
		loc.setStato(località.getStato());
		return loc;
	}

	public Localita convert(LocalitàDTO localitàDTO) {
		Localita località = new Localita();
		updateEntityBasicFields(localitàDTO, località);
		return località;
	}

	private void updateEntityBasicFields(LocalitàDTO localitàDTO, Localita localitàEntity) {
		localitàEntity.setDescrizione(localitàDTO.getDescrizione());
		localitàEntity.setNome(localitàDTO.getNome());
		localitàEntity.setProvincia(localitàDTO.getProvincia());
		localitàEntity.setStato(localitàDTO.getStato());
	}

	//aereoporto
	@Override
	public int saveAeroporto(AeroportoDTO aeroportoDTO) {
		Aeroporto aeroporto = convert(aeroportoDTO);
		em.persist(aeroporto);
		return aeroporto.getIDAeroporto();
	}

	@Override
	public void updateBasicInformationsAeroporto(AeroportoDTO aeroportoDTO) {
		Aeroporto aeroporto = findAeroportoEntity(aeroportoDTO.getID());
		updateEntityBasicFields(aeroportoDTO, aeroporto);
		em.merge(aeroporto);
	}

	@Override
	public void deleteAeroporto(int aeroportoDTOID) {
		em.remove(findAeroportoEntity(aeroportoDTOID));
	}

	@Override
	public AeroportoDTO findAeroporto(int aeroportoDTOID) {
		return convert(findAeroportoEntity(aeroportoDTOID));
	}

	@Override
	public List<AeroportoDTO> findAllAeroporto() {
		List<Aeroporto> aeroporti = em.createNamedQuery(Aeroporto.FIND_ALL, Aeroporto.class).getResultList();
		return ConverterFactory.convertList(aeroporti, new ConverterFactory.ConverterCallback<Aeroporto, AeroportoDTO>() {

			@Override
			public AeroportoDTO autoConvert(Aeroporto dto) {
				return convert(dto);
			}
		});
	}

	public Aeroporto findAeroportoEntity(int aeroportoID) {
		return em.find(Aeroporto.class, aeroportoID);
	}

	public AeroportoDTO convert(Aeroporto aeroporto) {
		AeroportoDTO aeroportoDTO = new AeroportoDTO();
		aeroportoDTO.setID(aeroporto.getIDAeroporto());
		aeroportoDTO.setIDlocalità(aeroporto.getLocalita().getIDLocalita());
		aeroportoDTO.setName(aeroporto.getNome());
		return aeroportoDTO;
	}

	public Aeroporto convert(AeroportoDTO aeroportoDTO) {
		Aeroporto aeroporto = new Aeroporto();
		updateEntityBasicFields(aeroportoDTO, aeroporto);
		return aeroporto;
	}

	private void updateEntityBasicFields(AeroportoDTO aeroportoDTO, Aeroporto aeroporto) {
		aeroporto.setNome(aeroportoDTO.getName());
		aeroporto.setLocalita(findLocalitaEntity(aeroportoDTO.getIDlocalità()));
	}

	//compagnia
	@Override
	public int saveCompagnia(CompagniaDTO compagniaDTO) {
		Compagnia compagnia = convert(compagniaDTO);
		em.persist(compagnia);
		return compagnia.getIDCompagnia();
	}

	@Override
	public void updateBasicInformationsCompagnia(CompagniaDTO compagniaDTO) {
		Compagnia compagnia = findCompagniaEntity(compagniaDTO.getID());
		updateEntityBasicFields(compagniaDTO, compagnia);
		em.merge(compagnia);
	}

	@Override
	public void deleteCompagnia(int compagniaDTOID) {
		em.remove(findCompagniaEntity(compagniaDTOID));
	}

	@Override
	public CompagniaDTO findCompagnia(int compagniaDTOID) {
		return convert(findCompagniaEntity(compagniaDTOID));
	}

	@Override
	public List<CompagniaDTO> findAllCompagnia() {
		List<Compagnia> compagnie = em.createNamedQuery(Compagnia.FIND_ALL, Compagnia.class).getResultList();
		return ConverterFactory.convertList(compagnie, new ConverterFactory.ConverterCallback<Compagnia, CompagniaDTO>() {
			@Override
			public CompagniaDTO autoConvert(Compagnia dto) {
				return convert(dto);
			}
		});
	}

	public Compagnia findCompagniaEntity(int compagniaID) {
		return em.find(Compagnia.class, compagniaID);
	}

	public CompagniaDTO convert(Compagnia compagnia) {
		CompagniaDTO compagniaDTO = new CompagniaDTO();
		compagniaDTO.setNome(compagnia.getNome());
		compagniaDTO.setID(compagnia.getIDCompagnia());
		return compagniaDTO;
	}

	public Compagnia convert(CompagniaDTO compagniaDTO) {
		Compagnia compagnia = new Compagnia();
		updateEntityBasicFields(compagniaDTO, compagnia);
		return compagnia;
	}

	private void updateEntityBasicFields(CompagniaDTO compagniaDTO, Compagnia compagnia) {
		compagnia.setNome(compagniaDTO.getNome());
	}

	//hotel
	@Override
	public int saveHotel(HotelProdDTO pHotelDTO) {
		Hotel hotel = new Hotel();
		System.out.println("In saveHotel ci arrivo!");	
		hotel = convert(pHotelDTO);
		
		em.persist(hotel);
		return hotel.getIDHotel();
	}

	@Override
	public void updateBasicInformationsHotel(HotelProdDTO pHotelDTO) {
		Hotel hotel = findHotelEntity(pHotelDTO.getID());
		updateEntityBasicFields(pHotelDTO, hotel);
		em.merge(hotel);
	}

	@Override
	public void deleteHotel(int pHotelDTOID) {
		em.remove(findHotelEntity(pHotelDTOID));
	}

	@Override
	public HotelProdDTO findHotel(int pHotelDTOID) {
		return convert(findHotelEntity(pHotelDTOID));
	}

	@Override
	public List<HotelProdDTO> findAllHotel() {
		List<Hotel> hotels = em.createNamedQuery(Hotel.FIND_ALL, Hotel.class).getResultList();
		return ConverterFactory.convertList(hotels, new ConverterFactory.ConverterCallback<Hotel, HotelProdDTO>() {

			@Override
			public HotelProdDTO autoConvert(Hotel dto) {
				return convert(dto);
			}
		});
	}

	public Hotel findHotelEntity(int hotelID) {
		return em.find(Hotel.class, hotelID);
	}

	public Hotel convert(HotelProdDTO hotelDTO) {
		Hotel hotel = new Hotel();
		
		updateEntityBasicFields(hotelDTO, hotel);
		return hotel;
	}

	public HotelProdDTO convert(Hotel hotel) {
		try{
		HotelProdDTO hotelDTO = new HotelProdDTO();
		hotelDTO.setID(hotel.getIDHotel());
		hotelDTO.setLocalita(convert(hotel.getLocalita()));
		hotelDTO.setLocalitàID(hotel.getLocalita().getIDLocalita());
		hotelDTO.setNome(hotel.getNome());
		hotelDTO.setNumeroCivico(hotel.getNumeroCivico());
		hotelDTO.setVia(hotel.getVia());
		hotelDTO.setEmailImpiegato(hotel.getUtente().getEmail());
		return hotelDTO;}
		catch(Exception e ){}
		return new HotelProdDTO();
	}

	private void  updateEntityBasicFields(HotelProdDTO hotelDTO, Hotel hotel) {
		try{
		System.out.print("Converto in ent.");
		hotel.setLocalita(findLocalitaEntity(hotelDTO.getLocalitàID()));
		hotel.setNome(hotelDTO.getNome());
		hotel.setNumeroCivico(hotelDTO.getNumeroCivico());
		hotel.setVia(hotelDTO.getVia());
		hotel.setUtente(findUtenteEntity(hotelDTO.getEmailImpiegato()));
		System.out.print("Convertito in ent.");
		}catch(Exception e){}				
	}

	//tour
	@Override
	public int saveTour(TourProdDTO pTourDTO) {
		Tour tour = convert(pTourDTO);
		em.persist(tour);
		return tour.getIDTour();
	}

	@Override
	public void updateBasicInformationsTour(TourProdDTO pTourDTO) {
		Tour tour = findTourEntity(pTourDTO.getID());
		updateEntityBasicFields(pTourDTO, tour);
		em.merge(tour);
	}

	@Override
	public void deleteTour(int pTourDTOID) {
		em.remove(findTourEntity(pTourDTOID));
	}

	@Override
	public TourProdDTO findTour(int pTourDTOID) {
		return convert(findTourEntity(pTourDTOID));
	}

	@Override
	public List<TourProdDTO> findAllTour() {
		List<Tour> tour = em.createNamedQuery(Tour.FIND_ALL, Tour.class).getResultList();
		return ConverterFactory.convertList(tour, new ConverterFactory.ConverterCallback<Tour, TourProdDTO>() {

			@Override
			public TourProdDTO autoConvert(Tour dto) {
				return convert(dto);
			}
		});
	}

	public Tour findTourEntity(int pTourID) {
		return em.find(Tour.class, pTourID);
	}

	public Tour convert(TourProdDTO tourDTO) {
		Tour tour = new Tour();
		updateEntityBasicFields(tourDTO, tour);
		return tour;
	}

	public TourProdDTO convert(Tour tour) {
		TourProdDTO tourDTO = new TourProdDTO();
		tourDTO.setDescrizione(tour.getDescrizione());
		tourDTO.setEmailImpiegato(tour.getUtente().getEmail());
		tourDTO.setID(tour.getIDTour());
		tourDTO.setLocalita(convert(tour.getLocalita()));
		tourDTO.setLocalitàID(tour.getLocalita().getIDLocalita());
		return tourDTO;
	}

	private void updateEntityBasicFields(TourProdDTO tourDTO, Tour tour) {
		tour.setDescrizione(tourDTO.getDescrizione());
		tour.setLocalita(findLocalitaEntity(tourDTO.getLocalitàID()));
		tour.setUtente(findUtenteEntity(tourDTO.getEmailImpiegato()));
	}

	//tratta
	@Override
	public int saveTratta(TrattaProdDTO pTrattaDTO) {
		TrattaVolo tratta = convert(pTrattaDTO);
		em.persist(tratta);
		return tratta.getIDTratta();
	}

	@Override
	public void updateBasicInformationsTratta(TrattaProdDTO pTrattaDTO) {
		TrattaVolo tratta = findTrattaEntity(pTrattaDTO.getID());
		updateEntityBasicFields(pTrattaDTO, tratta);
		em.merge(tratta);
	}

	@Override
	public void deleteTratta(int pTrattaDTOID) {
		em.remove(findTrattaEntity(pTrattaDTOID));
	}

	@Override
	public TrattaProdDTO findTratta(int pTrattaDTOID) {
		return convert(findTrattaEntity(pTrattaDTOID));
	}

	@Override
	public List<TrattaProdDTO> findAllTratta() {
		List<TrattaVolo> tratteVoli = em.createNamedQuery(TrattaVolo.FIND_ALL, TrattaVolo.class).getResultList();
		return ConverterFactory.convertList(tratteVoli, new ConverterFactory.ConverterCallback<TrattaVolo, TrattaProdDTO>() {
			@Override
			public TrattaProdDTO autoConvert(TrattaVolo dto) {
				return convert(dto);
			}
		});
	}

	public TrattaVolo findTrattaEntity(int pTrattaID) {
		return em.find(TrattaVolo.class, pTrattaID);
	}

	public TrattaVolo convert(TrattaProdDTO pTrattaDTO) {
		TrattaVolo tratta = new TrattaVolo();
		updateEntityBasicFields(pTrattaDTO, tratta);
		return tratta;
	}

	public TrattaProdDTO convert(TrattaVolo pTratta) {
		TrattaProdDTO trattaDTO = new TrattaProdDTO();
		trattaDTO.setAdAeroportoID(pTratta.getAdAeroporto().getIDAeroporto());
		trattaDTO.setDaAeroportoID(pTratta.getDaAeroporto().getIDAeroporto());
		trattaDTO.setID(pTratta.getIDTratta());
		trattaDTO.setCompagniaID(pTratta.getCompagnia().getIDCompagnia());
		return trattaDTO;
	}

	private void updateEntityBasicFields(TrattaProdDTO pTrattaDTO, TrattaVolo tratta) {
		tratta.setAdAeroporto(findAeroportoEntity(pTrattaDTO.getAdAeroportoID()));
		tratta.setDaAeroporto(findAeroportoEntity(pTrattaDTO.getDaAeroportoID()));
		tratta.setCompagnia(findCompagniaEntity(pTrattaDTO.getCompagniaID()));
		tratta.setUtente(findUtenteEntity(pTrattaDTO.getEmailImpiegato()));
	}
	
	public List<TrattaProdDTO> findAllTratte(){
		List<TrattaVolo> tratteVoli = em.createNamedQuery(TrattaVolo.FIND_ALL, TrattaVolo.class).getResultList();
		List<TrattaProdDTO> tratteDTO= new ArrayList<TrattaProdDTO>();
		for(TrattaVolo t: tratteVoli){
			TrattaProdDTO tDTO= new TrattaProdDTO();
			tDTO.setID(t.getIDTratta());
			tDTO.setEmailImpiegato(t.getUtente().getEmail());
			tDTO.setaAeroporto(convertAeroporto(t.getAdAeroporto()));
			tDTO.setDaAeroporto(convertAeroporto(t.getDaAeroporto()));
			tDTO.setCompagnia(convertCompagnia(t.getCompagnia()));
			tratteDTO.add(tDTO);
		}
		return tratteDTO;
	}
	public TrattaProdDTO convertTratta(TrattaVolo pTratta) {
		TrattaProdDTO trattaDTO = new TrattaProdDTO();
		trattaDTO.setEmailImpiegato(pTratta.getUtente().getEmail());
		trattaDTO.setCompagnia(convertCompagnia(pTratta.getCompagnia()));
		trattaDTO.setaAeroporto(convertAeroporto(pTratta.getAdAeroporto()));
		trattaDTO.setDaAeroporto(convertAeroporto(pTratta.getDaAeroporto()));
		trattaDTO.setID(pTratta.getIDTratta());
		return trattaDTO;
	}

	public CompagniaDTO convertCompagnia(Compagnia compagnia) {
		CompagniaDTO compagniaDTO = new CompagniaDTO();
		compagniaDTO.setNome(compagnia.getNome());
		compagniaDTO.setID(compagnia.getIDCompagnia());
		return compagniaDTO;
	}
	
	public AeroportoDTO convertAeroporto(Aeroporto aeroporto) {
		AeroportoDTO aeroportoDTO = new AeroportoDTO();
		aeroportoDTO.setID(aeroporto.getIDAeroporto());
		aeroportoDTO.setIDlocalità(aeroporto.getLocalita().getIDLocalita());
		aeroportoDTO.setLocalita(convertiLocalita(aeroporto.getLocalita()));
		aeroportoDTO.setName(aeroporto.getNome());
		return aeroportoDTO;
	}
	public LocalitàDTO convertiLocalita(Localita loc){
		LocalitàDTO locDTO= new LocalitàDTO();
		locDTO.setID(loc.getIDLocalita());
		locDTO.setNome(loc.getNome());
		locDTO.setDescrizione(loc.getDescrizione());
		locDTO.setStato(loc.getStato());
		locDTO.setProvincia(loc.getProvincia());
		return locDTO;
	}
	
}
